﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;

namespace MergeDir
{
    /// <summary>
    /// 标记该属性为命令行输入参数
    /// </summary>
    [AttributeUsage(AttributeTargets.Property)]
    public sealed class CommandArgumentElementAttribute : Attribute
    {
        /// <summary>
        /// 标记该属性可以从控制台参数中进行获取
        /// </summary>
        /// <param name="name">控制台参数名称</param>
        public CommandArgumentElementAttribute(string name)
        {
            Name = name;
        }

        /// <summary>
        /// 控制台参数名称
        /// </summary>
        public string Name { get; }

        /// <summary>
        /// 参数默认值，当控制台没有输入相关参数时，该值将被赋值到当前属性
        /// </summary>
        public object DefaultValue { get; set; }

        /// <summary>
        /// 该参数的帮助信息
        /// </summary>
        public string Help { get; set; }

        /// <summary>
        /// 参数是否必填
        /// </summary>
        public bool IsRequired { get; set; }
    }

    class CmdArgumentInfo
    {
        public CmdArgumentInfo(PropertyInfo property, CommandArgumentElementAttribute attribute)
        {
            Property = property;
            Attribute = attribute;
        }

        public PropertyInfo Property { get; }

        public CommandArgumentElementAttribute Attribute { get; }
    }

    /// <summary>
    /// 控制台参数对象基类
    /// </summary>
    public abstract class CommandArgument
    {
        private readonly string _exeHelp;
        private readonly bool _isHelpPrinted = false;
        private readonly List<CmdArgumentInfo> _cmdArgumentInfos = new List<CmdArgumentInfo>();

        protected CommandArgument(string exeHelp)
        {
            _exeHelp = exeHelp;
            var printHelp = false;
            var cmdArgs = Environment.GetCommandLineArgs();
            if (cmdArgs.Length == 2 && string.Equals("--help", cmdArgs[1], StringComparison.OrdinalIgnoreCase))
            {
                printHelp = true;
            }
            else
            {
                IsValid = true;
            }

            var props = this.GetType().GetProperties();
            foreach (var prop in props)
            {
                if (!(prop.GetCustomAttributes(typeof(CommandArgumentElementAttribute), false).FirstOrDefault() is
                    CommandArgumentElementAttribute cmdArg)) continue;
                _cmdArgumentInfos.Add(new CmdArgumentInfo(prop, cmdArg));

                if (printHelp) continue;

                var index = IndexOf(cmdArgs, $"--{cmdArg.Name}");
                if (index < 0 || cmdArgs.Length <= index + 1)
                {
                    if (cmdArg.IsRequired)
                    {
                        IsValid = false;
                        Output($"参数{cmdArg.Name}是必填的，但控制台没有提供", ConsoleColor.Red);
                    }

                    if (cmdArg.DefaultValue != null)
                    {
                        prop.SetValue(this, cmdArg.DefaultValue, null);
                    }

                    continue;
                }

                try
                {
                    var value = Convert.ChangeType(cmdArgs[index + 1], prop.PropertyType);
                    prop.SetValue(this, value, null);
                }
                catch (Exception ex)
                {
                    IsValid = false;
                    Output($"设置参数{cmdArg.Name}出错：{ex.Message}");
                }
            }

            if (!printHelp) return;
            PrintHelp();
            _isHelpPrinted = true;
        }

        int IndexOf(string[] array, string find)
        {
            for (var i = 0; i < array.Length; i++)
            {
                if (string.Equals(array[i], find, StringComparison.OrdinalIgnoreCase)) return i;
            }

            return -1;
        }

        /// <summary>
        /// 打印帮助信息
        /// </summary>
        public void PrintHelp()
        {
            if (_isHelpPrinted) return;
            Console.WriteLine($"使用示例：{Path.GetFileName(Assembly.GetEntryAssembly()?.Location)} --arg1 1 --arg2 2");
            Console.WriteLine();
            if (!string.IsNullOrWhiteSpace(_exeHelp))
            {
                Console.WriteLine(_exeHelp);
                Console.WriteLine();
            }
            Console.WriteLine("程序支持的参数清单");
            Console.WriteLine("----------------");
            Console.WriteLine($"  参数名称\t必须\t默认值\t参数帮助");
            foreach (var argumentInfo in _cmdArgumentInfos)
            {
                Console.WriteLine(
                    $"  --{argumentInfo.Attribute.Name}\t{(argumentInfo.Attribute.IsRequired ? "是  " : "否  ")}\t{argumentInfo.Attribute.DefaultValue}\t{argumentInfo.Attribute.Help}");
            }
        }

        void Output(string message, ConsoleColor color = ConsoleColor.Gray)
        {
            Console.ForegroundColor = color;
            Console.WriteLine(message);
            Console.ForegroundColor = ConsoleColor.Gray;
        }

        /// <summary>
        /// 获取所有必填参数是否都有输入
        /// </summary>
        public bool IsValid { get; }
    }
}
